home *** CD-ROM | disk | FTP | other *** search
- /*
- trigger.c
-
- Copyright (c) 2000 Dug Song <dugsong@monkey.org>
-
- $Id: trigger.c,v 1.8 2000/05/18 20:20:04 dugsong Exp $
- */
-
- #include "config.h"
- #include <sys/types.h>
- #include <sys/uio.h>
- #include <stdlib.h>
- #ifdef HAVE_ERR_H
- #include <err.h>
- #endif
- #include <libnet.h>
- #include <nids.h>
- #include "options.h"
- #include "decode.h"
- #include "record.h"
- #include "tcp_raw.h"
- #include "trigger.h"
-
- #define SERVICES_FILE "dsniff.services"
-
- struct trigger {
- int num;
- struct decode *decode;
- };
-
- static struct trigger ip_triggers[32];
- static struct trigger udp_triggers[512];
- static struct trigger tcp_triggers[512];
- static struct trigger rpc_triggers[32];
-
- static u_int ip_cnt = 0;
- static u_int udp_cnt = 0;
- static u_int tcp_cnt = 0;
- static u_int rpc_cnt = 0;
-
- static int
- trigger_compare(const void *a, const void *b)
- {
- struct trigger *p, *q;
-
- q = (struct trigger *)a;
- p = (struct trigger *)b;
-
- if (p->num < q->num) {
- return (-1);
- }
- else if (p->num > q->num) {
- return (1);
- }
- return (0);
- }
-
- int
- trigger_set_ip(int num, char *name)
- {
- struct trigger *t, tr;
-
- tr.num = num;
-
- if ((tr.decode = getdecodebyname(name)) == NULL) {
- warnx("trigger_set_ip: unknown decode: %s", name);
- return (0);
- }
- t = (struct trigger *) bsearch(&tr, &ip_triggers, ip_cnt,
- sizeof(tr), trigger_compare);
- if (t != NULL) {
- if (Opt_debug)
- warnx("trigger_set_ip: proto %d already set", num);
- return (0);
- }
- if (ip_cnt == sizeof(ip_triggers) / sizeof(tr)) {
- warnx("trigger_set_ip: ip_triggers full");
- return (0);
- }
- ip_triggers[ip_cnt++] = tr;
-
- qsort(&ip_triggers, ip_cnt, sizeof(tr), trigger_compare);
-
- if (Opt_debug)
- warnx("trigger_set_ip: proto %d -> %s", num, name);
-
- return (1);
- }
-
- int
- trigger_set_udp(int num, char *name)
- {
- struct trigger *t, tr;
-
- tr.num = num;
-
- if ((tr.decode = getdecodebyname(name)) == NULL) {
- warnx("trigger_set_udp: unknown decode: %s", name);
- return (0);
- }
- t = (struct trigger *) bsearch(&tr, &udp_triggers, udp_cnt,
- sizeof(tr), trigger_compare);
- if (t != NULL) {
- if (Opt_debug)
- warnx("trigger_set_udp: port %d already set", num);
- return (0);
- }
- if (udp_cnt == sizeof(udp_triggers) / sizeof(tr)) {
- warnx("trigger_set_udp: udp_triggers full");
- return (0);
- }
- udp_triggers[udp_cnt++] = tr;
-
- qsort(&udp_triggers, udp_cnt, sizeof(tr), trigger_compare);
-
- if (Opt_debug)
- warnx("trigger_set_udp: port %d -> %s", num, name);
-
- return (1);
- }
-
- int
- trigger_set_tcp(int num, char *name)
- {
- struct trigger *t, tr;
-
- tr.num = num;
-
- if ((tr.decode = getdecodebyname(name)) == NULL) {
- warnx("trigger_set_tcp: unknown decode: %s", name);
- return (0);
- }
- t = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
- if (t != NULL) {
- if (Opt_debug)
- warnx("trigger_set_tcp: port %d already set", num);
- return (0);
- }
- if (tcp_cnt == sizeof(tcp_triggers) / sizeof(tr)) {
- warnx("trigger_set_tcp: tcp_triggers full");
- return (0);
- }
- tcp_triggers[tcp_cnt++] = tr;
-
- qsort(&tcp_triggers, tcp_cnt, sizeof(tr), trigger_compare);
-
- if (Opt_debug)
- warnx("trigger_set_tcp: port %d -> %s", num, name);
-
- return (1);
- }
-
- int
- trigger_set_rpc(int num, char *name)
- {
- struct trigger *t, tr;
-
- tr.num = num;
-
- if ((tr.decode = getdecodebyname(name)) == NULL) {
- warnx("trigger_set_tcp: unknown decode: %s", name);
- return (0);
- }
- t = (struct trigger *) bsearch(&tr, &rpc_triggers, rpc_cnt,
- sizeof(tr), trigger_compare);
- if (t != NULL) {
- if (Opt_debug)
- warnx("trigger_set_rpc: RPC program %d already set",
- num);
- return (0);
- }
- if (rpc_cnt == sizeof(rpc_triggers) / sizeof(tr)) {
- warnx("trigger_set_rpc: rpc_triggers full");
- return (0);
- }
- rpc_triggers[rpc_cnt++] = tr;
-
- qsort(&rpc_triggers, rpc_cnt, sizeof(tr), trigger_compare);
-
- if (Opt_debug)
- warnx("trigger_set_rpc: program %d -> %s", num, name);
-
- return (1);
- }
-
- void
- trigger_dump(void)
- {
- FILE *f;
- int i;
-
- if ((f = fopen(SERVICES_FILE, "w")) == NULL) {
- warn("trigger_dump: couldn't open " SERVICES_FILE);
- return;
- }
- fprintf(f, "# $Id: trigger.c,v 1.8 2000/05/18 20:20:04 dugsong Exp $\n"
- "#\n# Network services, dsniff style\n#\n");
-
- for (i = 0; i < ip_cnt; i++) {
- fprintf(f, "%s\t\t%d/ip\n", ip_triggers[i].decode->dc_name,
- ip_triggers[i].num);
- }
- for (i = 0; i < udp_cnt; i++) {
- fprintf(f, "%s\t\t%d/udp\n", udp_triggers[i].decode->dc_name,
- udp_triggers[i].num);
- }
- for (i = 0; i < tcp_cnt; i++) {
- fprintf(f, "%s\t\t%d/tcp\n", tcp_triggers[i].decode->dc_name,
- tcp_triggers[i].num);
- }
- for (i = 0; i < rpc_cnt; i++) {
- fprintf(f, "%s\t\t%d/rpc\n", rpc_triggers[i].decode->dc_name,
- rpc_triggers[i].num);
- }
- fclose(f);
- }
-
- void
- trigger_ip(struct ip *ip)
- {
- struct trigger *t, tr;
- u_char *buf;
- int len;
-
- tr.num = ip->ip_p;
-
- t = (struct trigger *) bsearch(&tr, &ip_triggers, ip_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL)
- return;
-
- buf = (u_char *)ip + (ip->ip_hl * 4);
- len = ntohs(ip->ip_len) - (ip->ip_hl * 4);
-
- if (Opt_debug)
- warnx("trigger_ip: decoding proto %d as %s",
- tr.num, t->decode->dc_name);
-
- if ((len = t->decode->dc_func(buf, len)) > 0) {
- record(ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_p,
- 0, 0, t->decode->dc_name, Buf, len);
- }
- }
-
- /* libnids needs a nids_register_udp()... */
- void
- trigger_udp(struct ip *ip)
- {
- struct trigger *t, tr;
- struct udphdr *udp;
- u_char *buf;
- int len, ip_hl = ip->ip_hl * 4;
-
- len = ntohs(ip->ip_len) - ip_hl;
-
- if (ip->ip_p != IPPROTO_UDP || len < sizeof(*udp))
- return;
-
- buf = (u_char *)ip + ip_hl;
- udp = (struct udphdr *)buf;
-
- if (len != ntohs(udp->uh_ulen))
- return;
-
- tr.num = ntohs(udp->uh_dport);
-
- t = (struct trigger *) bsearch(&tr, &udp_triggers, udp_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL) {
- tr.num = 0 - (int) ntohs(udp->uh_sport);
- t = (struct trigger *) bsearch(&tr, &udp_triggers, udp_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL)
- return;
- }
- buf += sizeof(*udp);
- len -= sizeof(*udp);
-
- if (Opt_debug)
- warnx("trigger_udp: decoding port %d as %s",
- tr.num, t->decode->dc_name);
-
- if ((len = t->decode->dc_func(buf, len)) > 0) {
- record(ip->ip_src.s_addr, ip->ip_dst.s_addr, IPPROTO_UDP,
- ntohs(udp->uh_sport), ntohs(udp->uh_dport),
- t->decode->dc_name, Buf, len);
- }
- }
-
- static void
- trigger_tcp_half(struct tuple4 *addr, struct half_stream *hs,
- struct trigger *t)
- {
- u_char *buf;
- int len;
-
- buf = hs->data;
- len = hs->count - hs->offset;
-
- if (hs->bufsize > len)
- buf[len] = '\0';
-
- if (Opt_debug)
- warnx("trigger_tcp: decoding port %d as %s",
- addr->dest, t->decode->dc_name);
-
- if ((len = t->decode->dc_func(buf, len)) > 0) {
- record(addr->saddr, addr->daddr, IPPROTO_TCP,
- addr->source, addr->dest, t->decode->dc_name, Buf, len);
- }
- hs->collect = 0;
- }
-
- void
- trigger_tcp(struct tcp_stream *ts, void **conn_save)
- {
- struct trigger *ct, *st, tr;
-
- tr.num = ts->addr.dest;
- ct = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
-
- tr.num = 0 - (int) ts->addr.dest;
- st = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
-
- switch (ts->nids_state) {
-
- case NIDS_JUST_EST:
- if (ct != NULL) {
- ts->server.collect = 1;
- }
- if (st != NULL) {
- ts->client.collect = 1;
- }
- break;
-
- case NIDS_DATA:
- if (ct != NULL && ts->server.count_new) {
- if (ts->server.count - ts->server.offset >=
- Opt_snaplen) {
- trigger_tcp_half(&ts->addr, &ts->server, ct);
- }
- else nids_discard(ts, 0);
- }
- else if (st != NULL && ts->client.count_new) {
- if (ts->client.count - ts->client.offset >=
- Opt_snaplen) {
- trigger_tcp_half(&ts->addr, &ts->client, st);
- }
- else nids_discard(ts, 0);
- }
- break;
-
- default:
- if (ct != NULL && ts->server.count > 0) {
- trigger_tcp_half(&ts->addr, &ts->server, ct);
- }
- if (st != NULL && ts->client.count > 0) {
- trigger_tcp_half(&ts->addr, &ts->client, st);
- }
- break;
- }
- }
-
- void
- trigger_tcp_raw(struct ip *ip)
- {
- struct trigger *t, tr;
- struct tcphdr *tcp;
- struct iovec *iov;
- int len, ip_hl = ip->ip_hl * 4;
-
- len = ntohs(ip->ip_len) - ip_hl;
-
- if (ip->ip_p != IPPROTO_TCP || len < sizeof(*tcp))
- return;
-
- tcp = (struct tcphdr *)((u_char *)ip + ip_hl);
-
- tr.num = ntohs(tcp->th_dport);
-
- t = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL) {
- tr.num = 0 - (int) ntohs(tcp->th_sport);
- t = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL)
- return;
- }
- if ((iov = tcp_raw_input(ip, tcp, len)) == NULL)
- return;
-
- if (Opt_debug)
- warnx("trigger_tcp_raw: decoding port %d as %s",
- tr.num, t->decode->dc_name);
-
- if ((len = t->decode->dc_func(iov->iov_base, iov->iov_len)) > 0) {
- record(ip->ip_src.s_addr, ip->ip_dst.s_addr, IPPROTO_TCP,
- ntohs(tcp->th_sport), ntohs(tcp->th_dport),
- t->decode->dc_name, Buf, len);
- }
- free(iov->iov_base);
- free(iov);
- }
-
- static void
- trigger_tcp_raw_callback(u_long src, u_long dst,
- u_short sport, u_short dport,
- u_char *buf, int len)
- {
- struct trigger *t, tr;
-
- tr.num = dport;
-
- t = (struct trigger *) bsearch(&tr, &tcp_triggers, tcp_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL)
- return;
-
- if (Opt_debug)
- warnx("trigger_tcp_raw_timeout: decoding port %d as %s",
- tr.num, t->decode->dc_name);
-
- if ((len = t->decode->dc_func(buf, len)) > 0) {
- record(src, dst, IPPROTO_TCP, sport, dport,
- t->decode->dc_name, Buf, len);
- }
- }
-
- void
- trigger_tcp_raw_timeout(int signal)
- {
- tcp_raw_timeout(TRIGGER_TCP_RAW_TIMEOUT, trigger_tcp_raw_callback);
- alarm(TRIGGER_TCP_RAW_TIMEOUT);
- }
-
- void
- trigger_rpc(int program, int proto, int port)
- {
- struct trigger *t, tr;
-
- tr.num = program;
-
- t = (struct trigger *) bsearch(&tr, &rpc_triggers, rpc_cnt,
- sizeof(tr), trigger_compare);
- if (t == NULL)
- return;
-
- if (proto == IPPROTO_UDP) {
- trigger_set_udp(port, t->decode->dc_name);
- }
- else if (proto == IPPROTO_TCP) {
- trigger_set_tcp(port, t->decode->dc_name);
- }
- }
-
- static void
- trigger_init_default(void)
- {
- trigger_set_ip(89, "ospf");
-
- trigger_set_udp(111, "portmap");
- trigger_set_udp(-111, "portmap");
- trigger_set_udp(161, "snmp");
- trigger_set_udp(417, "mmxp");
- trigger_set_udp(2417, "mmxp");
- trigger_set_udp(520, "rip");
- trigger_set_udp(2001, "sniffer");
- trigger_set_udp(4000, "icq");
-
- trigger_set_tcp(21, "ftp");
- trigger_set_tcp(23, "telnet");
- trigger_set_tcp(80, "http");
- trigger_set_tcp(98, "http");
- trigger_set_tcp(3128, "http");
- trigger_set_tcp(8080, "http");
- trigger_set_tcp(106, "poppass");
- trigger_set_tcp(109, "pop");
- trigger_set_tcp(110, "pop");
- trigger_set_tcp(111, "portmap");
- trigger_set_tcp(-111, "portmap");
- trigger_set_tcp(119, "nntp");
- trigger_set_tcp(139, "smb");
- trigger_set_tcp(143, "imap");
- trigger_set_tcp(220, "imap");
- trigger_set_tcp(389, "ldap");
- trigger_set_tcp(417, "mmxp");
- trigger_set_tcp(2417, "mmxp");
- trigger_set_tcp(513, "rlogin");
- trigger_set_tcp(514, "rlogin");
- trigger_set_tcp(1080, "socks");
- trigger_set_tcp(1494, "citrix");
- trigger_set_tcp(1521, "oracle");
- trigger_set_tcp(1526, "oracle");
- trigger_set_tcp(2401, "cvs");
- trigger_set_tcp(4444, "napster");
- trigger_set_tcp(5555, "napster");
- trigger_set_tcp(6666, "napster");
- trigger_set_tcp(7777, "napster");
- trigger_set_tcp(8888, "napster");
- trigger_set_tcp(5190, "aim");
- trigger_set_tcp(9898, "aim");
- trigger_set_tcp(5432, "postgresql");
- trigger_set_tcp(5631, "pcanywhere");
- trigger_set_tcp(65301, "pcanywhere");
- trigger_set_tcp(6000, "x11");
- trigger_set_tcp(6001, "x11");
- trigger_set_tcp(6002, "x11");
- trigger_set_tcp(6003, "x11");
- trigger_set_tcp(6004, "x11");
- trigger_set_tcp(6005, "x11");
- trigger_set_tcp(6667, "irc");
- trigger_set_tcp(6668, "irc");
- trigger_set_tcp(6669, "irc");
-
- trigger_set_rpc(100005, "mountd");
- trigger_set_rpc(100009, "yppasswd");
- }
-
- void
- trigger_init(char *services)
- {
- FILE *f;
- char *name, *port, *proto, line[1024];
- int num;
-
- ip_cnt = 0;
- udp_cnt = 0;
- tcp_cnt = 0;
- rpc_cnt = 0;
-
- memset((char *)&ip_triggers, 0, sizeof(ip_triggers));
- memset((char *)&udp_triggers, 0, sizeof(udp_triggers));
- memset((char *)&tcp_triggers, 0, sizeof(tcp_triggers));
- memset((char *)&rpc_triggers, 0, sizeof(rpc_triggers));
-
- if (services == NULL) {
- trigger_init_default();
- return;
- }
- if ((f = fopen(services, "r")) == NULL)
- errx(1, "trigger_init: couldn't open %s", services);
-
- while (fgets(line, sizeof(line), f) != NULL) {
- if (line[0] == '#' || line[0] == '\n')
- continue;
-
- name = strtok(line, " \t");
- port = strtok(NULL, " \t/");
- proto = strtok(NULL, " \t#\n");
-
- if (!name || !port || !proto)
- continue;
-
- if ((num = atoi(port)) == 0)
- continue;
-
- if (strcasecmp(proto, "ip") == 0) {
- trigger_set_ip(num, name);
- }
- else if (strcasecmp(proto, "udp") == 0) {
- trigger_set_udp(num, name);
- }
- else if (strcasecmp(proto, "tcp") == 0) {
- trigger_set_tcp(num, name);
- }
- else if (strcasecmp(proto, "rpc") == 0) {
- trigger_set_rpc(num, name);
- }
- }
- fclose(f);
- }
-
-